<?php
namespace cubox;
use cubox\provider\webpack\Html;

class Webpack{

    public static $css = [];
    public static $beforeCss  = [];
    public static $js = [];
    public static $script = [];
    
    public static $fileList = [];
    
    protected string $name;

    protected string $html;
    protected array $param;
    protected string $savePath;
    protected string $webpackUrl;

    protected array $plugApp = [];

    protected string $templateFolder;
    protected string $templateFile;
    protected $cache;
 
    public function __construct($html,$param,$templateFile,$savePath,$webpackUrl)
    {
         
        $this->html = $html;
        $this->param = $param;
        $this->savePath = $savePath;
        $this->webpackUrl = $webpackUrl;   

        //通过html和template确定 webpack 文件的唯一性
        $this->name  = md5($html.$templateFile);
        $this->templateFile = $templateFile;
        $this->templateFolder = pathinfo($templateFile,PATHINFO_DIRNAME);
        
    }

    public function setName($name){
        $this->name =  $name;
    }

    public function setPlugApp(array $plugApp){
        $this->plugApp = $plugApp;
    }
 
    private function cache(){
        $config = Cubox::config('webpack');
        $cache = Cubox::cache($config->cache);
        return $cache;
    }


    public function pack():string{
        $cache = $this->cache();

        $cacheName  = 'webpack:'.$this->name;
        if (!$cache->exists($cacheName) || CUBOX_DEBUG){
            
            $html_data =  $this->parseXml($this->html);
    
            if (count($html_data)>0){
                 
                foreach($html_data as $item){

                    $basePath = $this->templateFolder;
                
                    if (isset($item['app'])){
                        $basePath =  ROOT.DS.APP.DS.$item['app'].DS.'template';
                    }

                    $filePath = File::realPath($item['path'],$basePath);
                    
                    //载入文件
                    if ($item['type']=='file'){
                        $this->packFile($filePath,$item);
                    }

                    //载入文件夹
                    if ($item['type']=='folder'){
                        

                        /**
                         * @TODO 暂时没有想好子文件夹怎么处理，等以后再说
                         
                        $sub = true;
                        //获取文件夹内的全部内容
                        if ($item['sub']=='false'){
                            $sub = false;
                        }
                        */


                        $folderPath = File::realPath($item['path'],$basePath);

                        //echo $folderPath;
                        $fileList   =  File::fileList($folderPath,'',false);
                        
                        if ($item['name']!=''){
                            $this->addScript($this->name,'let '.$item['name'].' = {};');
                        }

                        foreach($fileList as $file){
                            $param = array();
                            if ($item['name']!=''){
                                $param['name'] = $item['name'].'["'.pathinfo($folderPath.DS.$file,PATHINFO_FILENAME).'"]';
                            }
                            $this->packFile($folderPath.DS.$file,$param);
                        }
                         
                    }

                    
                    //载入插件
                    if ($item['type']=='plug'){

                        if (!isset($item['path'])) continue;
                        
                        $ext  =  pathinfo($item['path'],PATHINFO_EXTENSION);

                        $className = '\\cubox\\webpack\\'.ucfirst($ext);
                        if (!class_exists($className)) continue;

                        $variable = $className::variable();

                        $appList = empty($this->plugApp) ? $this->plugApp : array_keys(Cubox::getAppList());
                         
                        
                        if ($item['name']!='' && $variable){
                            $this->addScript($this->name,'let '.$item['name'].' = {};');
                        }
                      
                        foreach($appList as  $app){
                            
                            $filePath = File::realPath($item['path'],ROOT.DS.APP.DS.$app.DS.'template'.DS.'plug');
                             
                            if (file_exists($filePath)){
                                
                                $param = array();
                                if ($item['name']!='' && $variable){
                                    $param['name'] = $item['name'].'["'.$app.'"]';
                                }
                                $this->packFile($filePath,$param);
                            }
                            
                        }
                         
                    }
                    
                }
                
            }

            $html  = $this->makeFile();
            $cache->set($cacheName,$html);
            return   $html;
        }else{
            return $cache->get($cacheName)??'';
        }
        
    }

    /**
     * 直接对HTML内的Import进行打包
     */

    public function htmlImportPack(){
        //echo $this->templateFile;
        $driver = new Html($this->name,$this->templateFile,$this->webpackUrl,$this->param);
        $cache = Cubox::cache();
        $cacheName  = 'webpack.'.$this->name;
        $re = array();
        if (!$cache->exists($cacheName) || CUBOX_DEBUG){
            $cacheLab = false;
        }else{
            $cacheLab = true;
            try{
                $re = json_decode($cache->get($cacheName)??'',true)??[];
            }catch(\Exception $e){
                $re = [];
            }
        }

        $html = $driver->cssImport($this->html,$cacheLab);
        $html = $driver->jsImport($html,$cacheLab);

        if (!$cacheLab){
            $re['js']  = $this->makeJSFile();
            $re['css'] = $this->makeCSSFile();
            
            $cache->set($cacheName,json_encode($re));
        }
        $re['html'] =  $html;
        return $re;
    }


    private function packFile($file,$param){
        //print_r($param);
        $fileObject = self::fileDriver($this->name,$file,$this->webpackUrl,$param);
        $fileObject->import = false;
        $fileObject->pack();
    }

    public function makeFile():string{
        $html = $this->makeCssFile().$this->makeJsFile();
        return $html;
    }

    public function makeCssFile():string{
        $cssCode = '';
        if (isset(self::$beforeCss[$this->name]) && self::$beforeCss[$this->name]!='') $cssCode .= self::$beforeCss[$this->name];  
        if (isset(self::$css[$this->name]) && self::$css[$this->name]!='' )            $cssCode .= self::$css[$this->name]; 

        if ($cssCode!=''){

            if (!is_dir($this->savePath)){
                try{
                    mkdir($this->savePath,0777,true);
                }catch(\Exception $e){
                    throw new \Exception('创建文件夹失败');
                }   
            }

            file_put_contents($this->savePath.DS.$this->name.'.css',$cssCode);
            return  '<link rel="stylesheet" href="'.$this->webpackUrl.'/'.$this->name.'.css">'.PHP_EOL;
        }else{
            return  '';
        }
    } 

    public function makeJsFile():string{
        $jsCode = '';

        if (isset(self::$js[$this->name]) && self::$js[$this->name]!='') $jsCode .=self::$js[$this->name];
        if (isset(self::$script[$this->name]) && self::$script[$this->name]!='') $jsCode .=self::$script[$this->name];

        if ($jsCode!=""){
            
            if (!is_dir($this->savePath)){
                try{
                    mkdir($this->savePath,0777,true);
                }catch(\Exception $e){
                    throw new \Exception('创建文件夹失败');
                }   
            }

            file_put_contents($this->savePath.DS.$this->name.'.js',$jsCode);
            return '<script src="'.$this->webpackUrl.'/'.$this->name.'.js"></script>'.PHP_EOL;
        }else{
            return '';
        }

    }

    private function parseXml(string $html){
        $html = '<root>'.$html.'</root>';
        
        $data =  array();
        $index = 0;

        $xmls = simplexml_load_string($html);
         
        foreach($xmls->children() as $child) 
        {   
            
            $d= array();
            $d['type']= $child->getName();
            
            
            foreach($child->attributes() as $attrName => $attrValue) {
               
                $d[$attrName]= (string)$attrValue;
               
            }

            

            if ($d['type']=='folder' || $d['type']=='file' || $d['type']=='plug'){
                if ($d['path']!=''){
                    $data[$index] = $d;
                    $index++;
                }
            }
        }

        return $data;
    }

     


    public static function addCss($name,$css){

        if (!isset(self::$css[$name])){
            self::$css[$name] = '';
        }

        self::$css[$name] .= $css ."\n"; 
    }

    public static function addBeforeCss($name,$css){
        if (!isset(self::$beforeCss[$name])){
            self::$beforeCss[$name] = '';
        }

        self::$css[$name] .= $css ."\n"; 
    }


    public static function addJs($name,$js){

        if (!isset(self::$js[$name])){
            self::$js[$name] = '';
        }
        self::$js[$name] .= $js ."\n"; 
    }

    public static function addScript($name,$script){
        if (!isset(self::$script[$name])){
            self::$script[$name] = '';
        }

        self::$script[$name] .= $script ."\n"; 
    }

    public static function addFile($name,$file){
        if (!isset(self::$fileList[$name])){
            self::$fileList[$name] = [];
        }

        if (!self::inFileList($name,$file)){
            self::$fileList[$name][] = $file;
        }

        
    }

    public static function inFileList($name,$file){
        if (isset(self::$fileList[$name])){

            if (in_array($file,self::$fileList[$name])){
               
                return true;   
            }
           
        }
        return false;
    }

    public static function fileDriver($name,$file,$webpackUrl,$param=array()){
        $ext = pathinfo($file,PATHINFO_EXTENSION);
        $className = '\\cubox\\webpack\\'.ucfirst($ext);
        
        self::addFile($name,$file);

        if (!class_exists($className)){
            throw new \Exception('Webpack没有[.'.$ext.']文件的驱动');
        }

        return  new $className($name,$file,$webpackUrl,$param);
    }



    
}